package com.oig.sys.query.support;

import com.alibaba.fastjson.JSONObject;
import com.oig.common.exception.BadRequestException;
import com.oig.sys.query.constants.ExpressionEnum;
import com.oig.sys.query.support.module.ConditionExp;
import com.oig.sys.query.support.module.ConditionPropertyExp;
import com.oig.sys.query.support.module.QueryExpression;
import com.oig.sys.query.support.module.SqlAndParams;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class DefaultConditionCovert implements QueryConditionCovert {


    @Override
    public SqlAndParams whereSqlCovert(ConditionExp conditionExp, QueryExpression queryExpression) {
        SqlAndParams conditionSqlAndParams = new SqlAndParams();
        Map<String, Object> params = new HashMap<>();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(where) ;
        this.addToBuilder(stringBuilder, params, 0, conditionExp, queryExpression);
        conditionSqlAndParams.setSql(stringBuilder.toString());
        conditionSqlAndParams.setParams(params);
        return conditionSqlAndParams;
    }

    @Override
    public SqlAndParams addConditionCovert(SqlAndParams baseSqlAndParams, ConditionExp conditionExp, QueryExpression queryExpression) {
        if (baseSqlAndParams==null){
            return this.whereSqlCovert(conditionExp, queryExpression);
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(baseSqlAndParams.getSql());
        stringBuilder.append(ExpressionEnum.MongoSymbolEnum.getValueByKey(conditionExp.getKey()));  //最外层是不能是or的
        this.addToBuilder(stringBuilder, baseSqlAndParams.getParams(), 100, conditionExp, queryExpression);
        baseSqlAndParams.setSql(stringBuilder.toString());
        return baseSqlAndParams;
    }

    private int addToBuilder(StringBuilder stringBuilder, Map<String, Object> params, int i, ConditionExp conditionExp, QueryExpression queryExpression){
        if (i>0) stringBuilder.append(" (") ;
        for (int j=0; j<conditionExp.getExpList().size(); j++){
            ConditionPropertyExp propertyExp = conditionExp.getExpList().get(j) ;
            this.addProToBuilder(stringBuilder,String.format("%s_%s",i,j), params, propertyExp, queryExpression);
            if (j<conditionExp.getExpList().size()-1){
                stringBuilder.append(ExpressionEnum.MongoSymbolEnum.getValueByKey(conditionExp.getKey()));  //最外层是不能是or的
            }
        }
        if (i>0) stringBuilder.append(") ") ;
        i ++ ;
        if (conditionExp.getInnerCondition()!=null){
            for (ConditionExp sonCondition : conditionExp.getInnerCondition()){
                if (stringBuilder.length()>where.length()){
                    stringBuilder.append(ExpressionEnum.MongoSymbolEnum.getValueByKey(conditionExp.getKey()));
                }
                i = this.addToBuilder(stringBuilder, params, i,  sonCondition, queryExpression);
            }
        }
        return i;
    }


    @SuppressWarnings("unchecked")
    private void addProToBuilder(StringBuilder stringBuilder, String index, Map<String, Object> params, ConditionPropertyExp propertyExp, QueryExpression queryExpression){
        String tableFieldName = queryExpression.getTableField(propertyExp.getField()) ; //别名转成字段名
        if (tableFieldName==null){
            throw new BadRequestException(String.format("query param :%s not allow!", propertyExp.getField()));
        }
        if (ExpressionEnum.MongoSymbolEnum.BETWEEN.getMongoStr().equals(propertyExp.getSymbol())){
            String betweenStart = String.format("%s_start_%s", propertyExp.getField(), index);
            String betweenEnd = String.format("%s_end_%s", propertyExp.getField(), index);
            stringBuilder.append(String.format(" %s between :%s and :%s ", tableFieldName, betweenStart, betweenEnd)) ;
            List<Object>  value = (List<Object>) propertyExp.getValue() ;
            params.put(betweenStart, value.get(0)) ;
            params.put(betweenEnd, value.get(1)) ;
        } else if (ExpressionEnum.MongoSymbolEnum.IN.getMongoStr().equals(propertyExp.getSymbol())
                || ExpressionEnum.MongoSymbolEnum.NIN.getMongoStr().equals(propertyExp.getSymbol())) {
            String paramName = String.format("%s_%s", propertyExp.getField(), index);
            stringBuilder.append(String.format(" %s %s(:%s) ", tableFieldName,
                    ExpressionEnum.MongoSymbolEnum.getValueByKey(propertyExp.getSymbol()),
                    paramName));
            List<Object> vin = (List<Object>) propertyExp.getValue();
            params.put(paramName,vin);
        } else if (ExpressionEnum.MongoSymbolEnum.NULL.getMongoStr().equals(propertyExp.getSymbol())) {
            stringBuilder.append(String.format(" (%s %s or %s='') ", tableFieldName, ExpressionEnum.MongoSymbolEnum.getValueByKey(propertyExp.getSymbol()),tableFieldName));
        } else if (ExpressionEnum.MongoSymbolEnum.NOTNULL.getMongoStr().equals(propertyExp.getSymbol())){
            stringBuilder.append(String.format(" (%s %s and %s!='') ", tableFieldName, ExpressionEnum.MongoSymbolEnum.getValueByKey(propertyExp.getSymbol()),tableFieldName));
        } else if (ExpressionEnum.MongoSymbolEnum.JSON_CONTAINS.getMongoStr().equals(propertyExp.getSymbol())){
            //mysql8 才支持
            String paramName = String.format("%s_%s", propertyExp.getField(), index);
            List<Object> vc = (List<Object>) propertyExp.getValue();
            stringBuilder.append(String.format(" JSON_CONTAINS(%s, :%s) ", tableFieldName, paramName));
            params.put(paramName, JSONObject.toJSONString(vc));
        } else {
            String paramName = String.format("%s_%s", propertyExp.getField(), index);
            stringBuilder.append(String.format(" %s %s :%s ",
                    tableFieldName,
                    ExpressionEnum.MongoSymbolEnum.getValueByKey(propertyExp.getSymbol()),
                    paramName)) ;
            params.put(paramName, propertyExp.getValue()) ;
        }
    }





}
